package org.hismig.migration.executor;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;

import org.hismig.cfg.Table;
import org.hismig.migration.Context;
import org.hismig.migration.executor.ext.IExtExecutor;
import org.hismig.migration.parambuilder.IParamBuilder;
import org.hismig.migration.parambuilder.ParamBuildException;
import org.hismig.migration.result.TableResultInfo;
import org.hismig.migration.strategy.IStrategy;

/**
 * @declare: //TODO <br />
 *           This class created by Vansion.Hopihit on 2012-07-04 <br />
 *           <a href="mailto:vansionhopihit@gmail.com">Contact Me</a>
 * @version 1.0
 * @author Vansion.Hopihit
 * 
 */
public class TableExecutor extends TableExecutorBase {

	private List<IParamBuilder> paramBuilders;
	private IExtExecutor sourcePreExtExecutor;
	private IExtExecutor distPreExtExecutor;
	private IExtExecutor distAfterExtExecutor;
	private IExtExecutor sourceAfterExtExecutor;

	private IStrategy strategy;

	private Table table;

	private DBExecutorBase dbExecutorBase;

	private List<ITableExecutorListener> tableExecutorListeners = new ArrayList<ITableExecutorListener>();

	public List<IParamBuilder> getParamBuilders() {
		return paramBuilders;
	}

	public void setParamBuilders(List<IParamBuilder> paramBuilders) {
		this.paramBuilders = paramBuilders;
	}

	public IExtExecutor getSourcePreExtExecutor() {
		return sourcePreExtExecutor;
	}

	public void setSourcePreExtExecutor(IExtExecutor sourcePreExtExecutor) {
		this.sourcePreExtExecutor = sourcePreExtExecutor;
	}

	public IExtExecutor getDistPreExtExecutor() {
		return distPreExtExecutor;
	}

	public void setDistPreExtExecutor(IExtExecutor distPreExtExecutor) {
		this.distPreExtExecutor = distPreExtExecutor;
	}

	public IExtExecutor getDistAfterExtExecutor() {
		return distAfterExtExecutor;
	}

	public void setDistAfterExtExecutor(IExtExecutor distAfterExtExecutor) {
		this.distAfterExtExecutor = distAfterExtExecutor;
	}

	public IExtExecutor getSourceAfterExtExecutor() {
		return sourceAfterExtExecutor;
	}

	public void setSourceAfterExtExecutor(IExtExecutor sourceAfterExtExecutor) {
		this.sourceAfterExtExecutor = sourceAfterExtExecutor;
	}

	public TableResultInfo execute(Context context) {

		try {
			for (ITableExecutorListener tableExecutorListener : tableExecutorListeners) {
				tableExecutorListener.beforeTableExecuteStart(context, this);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		TableResultInfo tableResultInfo = new TableResultInfo(table.getName());

		tableResultInfo.setStartTime(System.currentTimeMillis());
		for (IParamBuilder paramBuilder : paramBuilders) {
			try {
				paramBuilder.paramBuild(context);
			} catch (ParamBuildException e) {
				tableResultInfo.addException(e);
				tableResultInfo.setEndTime(System.currentTimeMillis());
				return tableResultInfo;
			}
		}

		if (null != sourcePreExtExecutor) {

			try {
				for (ITableExecutorListener tableExecutorListener : tableExecutorListeners) {
					tableExecutorListener.beforeExtExecuteStart(context,
							sourcePreExtExecutor);
				}
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}

			try {
				tableResultInfo.setSourcePreResultInfo(sourcePreExtExecutor
						.execute(context));
			} catch (ExecutionException e) {
				tableResultInfo.addException(e);
				tableResultInfo.setEndTime(System.currentTimeMillis());
				return tableResultInfo;
			}

			try {
				for (ITableExecutorListener tableExecutorListener : tableExecutorListeners) {
					tableExecutorListener.afterExtExecuteEnd(tableResultInfo
							.getSourcePreResultInfo());
				}
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}

		if (null != distPreExtExecutor) {

			try {
				for (ITableExecutorListener tableExecutorListener : tableExecutorListeners) {
					tableExecutorListener.beforeExtExecuteStart(context,
							distPreExtExecutor);
				}
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}

			try {
				tableResultInfo.setDistPreResultInfo(distPreExtExecutor
						.execute(context));
			} catch (ExecutionException e) {
				tableResultInfo.addException(e);
				tableResultInfo.setEndTime(System.currentTimeMillis());
				return tableResultInfo;
			}

			try {
				for (ITableExecutorListener tableExecutorListener : tableExecutorListeners) {
					tableExecutorListener.afterExtExecuteEnd(tableResultInfo
							.getDistPreResultInfo());
				}
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}

		if (null != strategy) {
			tableResultInfo.setExecuteResultInfo(strategy
					.execute(context, this));
		}

		if (null != distAfterExtExecutor) {

			try {
				for (ITableExecutorListener tableExecutorListener : tableExecutorListeners) {
					tableExecutorListener.beforeExtExecuteStart(context,
							distAfterExtExecutor);
				}
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}

			try {
				tableResultInfo.setDistAfterResultInfo(distAfterExtExecutor
						.execute(context));
			} catch (ExecutionException e) {
				tableResultInfo.addException(e);
				tableResultInfo.setEndTime(System.currentTimeMillis());
				return tableResultInfo;
			}

			try {
				for (ITableExecutorListener tableExecutorListener : tableExecutorListeners) {
					tableExecutorListener.afterExtExecuteEnd(tableResultInfo
							.getDistAfterResultInfo());
				}
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}

		if (null != sourceAfterExtExecutor) {

			try {
				for (ITableExecutorListener tableExecutorListener : tableExecutorListeners) {
					tableExecutorListener.beforeExtExecuteStart(context,
							sourceAfterExtExecutor);
				}
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}

			try {
				tableResultInfo.setSourceAfterResultInfo(sourceAfterExtExecutor
						.execute(context));
			} catch (ExecutionException e) {
				tableResultInfo.addException(e);
				tableResultInfo.setEndTime(System.currentTimeMillis());
				return tableResultInfo;
			}

			try {
				for (ITableExecutorListener tableExecutorListener : tableExecutorListeners) {
					tableExecutorListener.afterExtExecuteEnd(tableResultInfo
							.getSourceAfterResultInfo());
				}
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}

		tableResultInfo.setEndTime(System.currentTimeMillis());

		try {
			for (ITableExecutorListener tableExecutorListener : tableExecutorListeners) {
				tableExecutorListener.afterTableExecuteEnd(tableResultInfo);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return tableResultInfo;
	}

	public IStrategy getStrategy() {
		return strategy;
	}

	public void setStrategy(IStrategy strategy) {
		this.strategy = strategy;
	}

	public Table getTable() {
		return table;
	}

	public void setTable(Table table) {
		this.table = table;
	}

	public DBExecutorBase getDbExecutorBase() {
		return dbExecutorBase;
	}

	public void setDbExecutorBase(DBExecutorBase dbExecutorBase) {
		this.dbExecutorBase = dbExecutorBase;
	}

	@Override
	public int getExtExecutorCount() {
		int count = 0;
		if (null != sourcePreExtExecutor) {
			count++;
		}

		if (null != distPreExtExecutor) {
			count++;
		}

		if (null != distAfterExtExecutor) {
			count++;
		}

		if (null != sourceAfterExtExecutor) {
			count++;
		}

		return count;
	}

	public void addListener(ITableExecutorListener tableExecutorListener) {
		if (!tableExecutorListeners.contains(tableExecutorListener)) {
			tableExecutorListeners.add(tableExecutorListener);
		}
	}

	public void removeListener(ITableExecutorListener tableExecutorListener) {
		if (tableExecutorListeners.contains(tableExecutorListener)) {
			tableExecutorListeners.remove(tableExecutorListener);
		}
	}
}
